home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / e10_edit.arc / E.ASM next >
Assembly Source File  |  1990-03-22  |  63KB  |  2,401 lines

  1. ;E 1.0.  Copyright (C) David Nye, 1990, all rights reserved.
  2. ;Assemble with TASM.  Link: tlink /t e (makes a .COM file).
  3.  
  4. IDEAL
  5. ;Constants
  6.  
  7. LINEWIDTH       EQU 80          ;Length of string storage for line
  8. SCREENLENGTH    EQU 24          ;Number of rows in display window
  9. MAXLINES        EQU 8096        ;Size of arrays of line pointers
  10. BUFFERLENGTH    EQU 1200h       ;Length of file buffer
  11. STACKSIZE       EQU 50h         ;Length of stack
  12. BELL            EQU 7           ;Some non-printing chars
  13. BS              EQU 8
  14. HT              EQU 9
  15. LF              EQU 10
  16. CR              EQU 13
  17. CRLF            EQU 0A0Dh
  18. CTRL_Z          EQU 26
  19. ESCAPE          EQU 27
  20. DEL             EQU 127
  21. PROGLENGTH = EndOfProgram - Orig + 100h  ;Length of .COM file
  22.  
  23.  
  24. ;Create a named string
  25. MACRO String Name, Text
  26.         LOCAL LL
  27. Name    db LL-Name-1, Text
  28. LL:
  29. ENDM
  30.  
  31. ;Make <Name> a byte ptr to <Length> bytes of storage after end of code.
  32. ;Like a .DATA? segment for .COM file, so uninitialized data doesn't take up
  33. ;room in the .COM file.
  34. MACRO B? Name, Length
  35.         LOCAL where
  36.         where = EndOfProgram + BuffersCount
  37. Name    EQU BYTE PTR where
  38.         BuffersCount = BuffersCount + Length
  39. ENDM
  40.  
  41. ;Like B? but for word storage
  42. MACRO W? Name, Length
  43.         LOCAL where
  44.         where = EndOfProgram + BuffersCount
  45. Name    EQU WORD PTR where
  46.         BuffersCount = BuffersCount + Length + Length
  47. ENDM
  48.  
  49. BuffersCount = 0
  50.  
  51.  
  52. MODEL TINY
  53. CODESEG
  54. ORG 100h
  55. Orig:
  56. jmp Start
  57.  
  58. String copyRight 'E 1.0.  Copyright (C) David Nye, 1990.  All rights reserved.'
  59.  
  60. ;Some defaults, use Debug to change
  61.  
  62. colorAttributes dw 1770h        ;Default status, text color video attributes
  63. tabSize         db 4            ;Tab increment
  64. inserting?      db -1           ;True if in insert mode
  65. autoIndent?     db -1           ;True if in autoindent mode
  66. startInText?    db 0            ;Set to true to start up in text mode
  67. zLMargin        db 8            ;Left margin setting for Alt Z
  68. zRMargin        db LINEWIDTH-8  ;Right margin setting for Alt Z
  69.  
  70.  
  71. ;Strings
  72.  
  73. String cantOpenMsg,     "Can't open file."
  74. String rdErrorMsg,      'Error reading file.'
  75. String fileErrorMsg,    'File error.'
  76. String noRoomMsg,       'Out of memory.'
  77. String notMarkingMsg,   'Not marking.'
  78. String setLabelMsg,     'Label (0-9): '
  79. String setTabsMsg,      'Tab width: '
  80. String newFileMsg,      'File name: '
  81. String gotoMsg          'Jump to what line? '
  82. String editingMsg       <'Help F1',186,'Editing: '>
  83. String findMsg          'Find: '
  84. String replaceMsg       'Replace with: '
  85. String notFoundMsg      'No more matching strings found.'
  86. String anyKeyMsg        'Press any key to continue.'
  87. String ctrlCMsg         '*Break*'
  88. String cancelledMsg     'Cancelled.'
  89. BAK                     db  '.BAK', 0
  90. comspec$                db  'COMSPEC='
  91. helpMsg                 db 'CURSOR left           left arrow, ^S    '
  92.                         db 'BLOCK begin                 @B          '
  93.                         db '  right               right arrow, ^D   '
  94.                         db '  copy block to buffer      @C *        '
  95.                         db '  word left           ^left arrow, ^A   '
  96.                         db '  delete block to buffer    @D *        '
  97.                         db '  word right          ^right arrow, ^F  '
  98.                         db '  insert block from buffer  @I *        '
  99.                         db '  tab right, left     Tab, Shift Tab    '
  100.                         db '  empty block buffer        @E *        '
  101.                         db '  start, end of line  Home, End         '
  102.                         db '  unmark                    @U          '
  103.                         db '  line up             up arrow, ^E      '
  104.                         db 'FIND                        @F +        '
  105.                         db '  line down           down arrow, ^X    '
  106.                         db '  replace                   @R +        '
  107.                         db '  page up             PgUp, ^R          '
  108.                         db '  find/replace all          @A +        '
  109.                         db '  page down           PgDn, ^C          '
  110.                         db 'SAVE and continue           @S          '
  111.                         db '  start of file       ^PgUp             '
  112.                         db '  save and exit             @X          '
  113.                         db '  end of file         ^PgDn             '
  114.                         db '  kill (no save at exit)    @K          '
  115.                         db 'DELETE                Del               '
  116.                         db '  open another file         @O          '
  117.                         db '  backspace           Backspace         '
  118.                         db 'JUMP to line #              @J          '
  119.                         db '  delete word left    ^[                '
  120.                         db '  set, goto label (0-9)     @L, @G      '
  121.                         db '  delete word right   ^], ^T            '
  122.                         db 'MARGIN set L, R             ^Home, ^End '
  123.                         db '  delete rest of line ^\                '
  124.                         db '  wrap paragraph            @W          '
  125.                         db '  delete line         ^-, ^Y            '
  126.                         db '  set tabs                  @T          '
  127.                         db '  undelete line       ^^                '
  128.                         db '  toggle autoindent         ^@          '
  129.                         db 'INSERT mode toggle    Ins               '
  130.                         db '  toggle text/prog mode     @Z          '
  131.                         db '  insert raw char     @= (+80h w shift) '
  132.                         db 'SHELL to DOS, run EFn.BAT   F2, F3-F6 * '
  133.                         db 80 dup (' ')
  134.                         db '@ = Alt, ^ = Ctrl, * = to/from file if s'
  135.                         db 'hifted, + = use last string if shifted. '
  136.                         db 'Status line flags:  Insert  Overwrite  C'
  137.                         db 'hanged  AutoIndent  [ LMargin  ] RMargin'
  138.  
  139.  
  140. ;EXEC function parameter block
  141.  
  142. EXECParams      dw 0
  143. EXECCmdLineOff  dw 0
  144. EXECCmdLineSeg  dw 0, -1, -1 , -1 , -1
  145. EXECBAT         db 0, '/c EF'
  146. EXECFnumber     db 'x.BAT '
  147. EXECFileName    db 20 dup (0)
  148.  
  149. ;Variables
  150.  
  151. newFile?        db 0            ;True if new file
  152. marking?        db 0            ;True if marking text
  153. changed?        db 0            ;True if original file has been changed
  154. isBAKed?        db 0            ;True if .BAK file already written
  155. needCopies?     db -1           ;True unless lines in buffer were just deleted
  156. autoReplace?    db 0            ;-1 if auto-replace with shift, 1 without shift
  157. noEscape?       db 0            ;True if prompt demands response
  158. labelTable      dw 10 dup (0)   ;Table of line pointers assigned to labels
  159.  
  160. ;These variables and buffers are allocated space following .COM file
  161. W? sstack, STACKSIZE            ;Stack goes here
  162. STACKTOP = EndOfProgram + BuffersCount
  163. B? attribNl, 1                  ;Text and status line attributes
  164. B? attribInv, 1
  165. W? cursorShape, 1               ;Line cursor parameters for color or mono
  166. B? fName?, 1                    ;True if file name given on command line
  167. B? justFound?, 1                ;True if no other commands since last Find
  168. B? swapped?, 1                  ;True if edited file swapped out during EXEC
  169. W? lMargin, 1                   ;Current margins
  170. W? rMargin, 1
  171. W? fHandle, 1                   ;File handle
  172. W? lastLine, 1                  ;Index of last line in file
  173. W? blockPtrsLast, 1             ;Index of last line in block buffer
  174. W? top, 1                       ;Index of first line on screen
  175. W? bottom, 1                    ;Index of last line on screen
  176. W? mark, 1                      ;Start of marking for block command
  177. W? here, 1                      ;Temporaries
  178. W? spTemp, 1
  179. W? comspecPtrOff, 1             ;Pointer to COMSPEC value: offset, segment
  180. W? comspecPtrSeg, 1
  181. W? bufferPtr, 1                 ;Multipurpose buffer pointer
  182. W? hereCol, 1
  183. W? topSegPtr, 1
  184. W? topSeg, 1
  185. W? topIndex, 1
  186. W? videoSegment, 1              ;Segment of system's video memory
  187. W? heapStart, 1                 ;Segment of start of heap
  188. W? heapPtr, 1                   ;Segment pointer to next free paragraph in heap
  189. B? fName, 20                    ;File name in ASCIIZ format
  190. ESSENTIALS = BuffersCount       ;Buffers above here not saved with shell + swap
  191. B? fNameBAK, LINEWIDTH          ;Current file with .BAK extension added
  192. B? fNameTemp, LINEWIDTH         ;File name for block read/writes, shell
  193. B? pad, LINEWIDTH               ;Scratch buffer
  194. B? findString, LINEWIDTH        ;Search string for Find command
  195. B? replaceString, LINEWIDTH     ;New string for Replace command
  196. W? linePtrs, MAXLINES           ;List of line pointers
  197. W? blockPtrs, MAXLINES          ;Line pointers for block or line deletes
  198. B? buffer, BUFFERLENGTH         ;File buffer
  199. ENDFBUFFER = BuffersCount
  200.  
  201. ;Jump tables:   ^ = Ctrl, @ = Alt, # = Shift.
  202. ctrlTable       dw na           ;Undefined
  203.                 dw WordLeft     ;^A
  204.                 dw na           ;^B
  205.                 dw PageDown     ;^C
  206.                 dw Right        ;^D
  207.                 dw Up           ;^E
  208.                 dw WordRight    ;^F
  209.                 dw na           ;^G or BEL
  210.                 dw BackSpace    ;^H or BS
  211.                 dw Tab          ;^I or HT
  212.                 dw na           ;^J or LF
  213.                 dw na           ;^K or VT
  214.                 dw na           ;^L or FF
  215.                 dw CRet         ;^M or CR
  216.                 dw na           ;^N or SO
  217.                 dw na           ;^O or SI
  218.                 dw na           ;^P
  219.                 dw na           ;^Q or DC1
  220.                 dw PageUp       ;^R or DC2
  221.                 dw Left         ;^S or DC3
  222.                 dw DeleteWordR  ;^T or DC4
  223.                 dw na           ;^U
  224.                 dw na           ;^V
  225.                 dw na           ;^W
  226.                 dw Down         ;^X or CAN
  227.                 dw DeleteLine   ;^Y
  228.                 dw na           ;^Z
  229.                 dw DeleteWordL  ;^[
  230.                 dw DeleteToEOL  ;^\
  231.                 dw DeleteWordR  ;^]
  232.                 dw UndeleteLine ;^^
  233.                 dw DeleteLine   ;^-
  234.  
  235. auxTable        dw 3 DUP (na)   ;Undefined
  236.                 dw AutoIndent   ;^@ or NUL
  237.                 dw 11 DUP (na)  ;Undefined
  238.                 dw ReverseTab   ;#Tab
  239.                 dw na           ;@Q
  240.                 dw Wrap         ;@W
  241.                 dw EmptyBuffer  ;@E
  242.                 dw Replace      ;@R
  243.                 dw SetTabs      ;@T
  244.                 dw na           ;@Y
  245.                 dw Unmark       ;@U
  246.                 dw InsertBlock  ;@I
  247.                 dw OtherFile    ;@O
  248.                 dw na           ;@P
  249.                 dw 4 DUP (na)   ;Undefined
  250.                 dw ReplaceAll   ;@A
  251.                 dw Save         ;@S
  252.                 dw DeleteBlock  ;@D
  253.                 dw Find         ;@F
  254.                 dw GotoLabel    ;@G
  255.                 dw Help         ;@H
  256.                 dw Jump         ;@J
  257.                 dw Kill         ;@K
  258.                 dw SetLabel     ;@L
  259.                 dw 5 DUP (na)   ;Undefined
  260.                 dw ToggleWPMode ;@Z
  261.                 dw Exit         ;@X
  262.                 dw Copy         ;@C
  263.                 dw na       ;@V
  264.                 dw BeginBlock   ;@B
  265.                 dw na           ;@N
  266.                 dw na           ;@M
  267.                 dw 8 DUP (na)   ;Undefined
  268.                 dw Help         ;F1
  269.                 dw Shell        ;F2
  270.                 dw F3BAT        ;F3
  271.                 dw F4BAT        ;F4
  272.                 dw F5BAT        ;F5
  273.                 dw F6BAT        ;F6
  274.                 dw na           ;F7
  275.                 dw na           ;F8
  276.                 dw na           ;F9
  277.                 dw na           ;F10
  278.                 dw 2 DUP (na)   ;Undefined
  279.                 dw HomeLine     ;Home
  280.                 dw Up           ;Up arrow
  281.                 dw PageUp       ;PgUp
  282.                 dw na           ;Undefined
  283.                 dw Left         ;Left arrow
  284.                 dw na           ;Undefined
  285.                 dw Right        ;Right arrow
  286.                 dw na           ;Undefined
  287.                 dw EndLine      ;End
  288.                 dw Down         ;Down arrow
  289.                 dw PageDown     ;PgDn
  290.                 dw ToggleIns    ;Ins
  291.                 dw Delete       ;Del
  292.                 dw na           ;#F1
  293.                 dw Shell        ;#F2
  294.                 dw F3BAT        ;#F3
  295.                 dw F4BAT        ;#F4
  296.                 dw F5BAT        ;#F5
  297.                 dw F6BAT        ;#F6
  298.                 dw na           ;#F7
  299.                 dw na           ;#F8
  300.                 dw na           ;#F9
  301.                 dw na           ;#F10
  302.                 dw 20 DUP (na)  ;[^Fn, @Fn]
  303.                 dw na           ;^PrtSc
  304.                 dw WordLeft     ;^Left arrow
  305.                 dw WordRight    ;^Right arrow
  306.                 dw SetRMargin   ;^End
  307.                 dw BottomFile   ;^PgDn
  308.                 dw SetLMargin   ;^Home
  309.                 dw 10 DUP (na)  ;[Alt numbers]
  310.                 dw na           ;@-
  311.                 dw InsertRaw    ;@=
  312.                 dw TopFile      ;^PgUp
  313.  
  314. ;******************************************************************************
  315.  
  316. Start:
  317.   mov ax, cs
  318.   mov ds, ax
  319.   mov es, ax
  320.   mov [EXECCmdLineSeg], ax      ;Store current segment for EXEC function
  321.   add ax, ((PROGLENGTH + ENDFBUFFER) SHR 4) + 1
  322.   mov [heapStart], ax           ;Compute start of free memory in paragraphs
  323.   mov sp, OFFSET STACKTOP
  324.   mov si, 80h                   ;Make pointer to command tail
  325.   mov cl, [si]                  ;Get filename length
  326.   sub ch, ch
  327.   mov [fName?], cl              ;Save a copy
  328.   mov al, ' '                   ;Skip leading blanks
  329. @@L1:
  330.   inc si
  331.   cmp al, [si]
  332.   loope @@L1
  333.   inc cx
  334.   mov di, OFFSET fName          ;Move command tail to FName
  335.   rep movsb
  336.   sub al, al                    ;Make ASCIIZ string
  337.   stosb
  338.   mov ax, 2523h                 ;Redirect Ctrl C handler
  339.   mov dx, OFFSET Cancel
  340.   int 21h
  341.   mov ah, 0Fh                   ;Set defaults for color or mono adapter
  342.   int 10h
  343.   mov bx, 0B000h                ;If mode 7 (= MDA or Herc), video seg=B000h,
  344.   mov cx, 0770h                 ;Use nl, inv video for text, status line
  345.   mov dx, 0C0Dh                 ;Set cursor shapes for mono
  346.   cmp al, 7
  347.   je @@L2
  348.   mov bx, 0B800h                ;Otherwise video seg=B800h,
  349.   mov cx, [colorAttributes]     ;Use default color attributes,
  350.   mov dx, 0607h                 ;Color cursor size
  351. @@L2:
  352.   xor ax, ax                    ;Code to allow E to run under DESQview,
  353.   mov es, ax                    ; contributed by Mike Robertson (bix:seamus)
  354.   mov ah, 0FEh
  355.   int 10
  356.   or al, al
  357.   jne @@L3a
  358.   mov ax, es
  359.   or ax, ax
  360.   je @@L3a
  361.   mov bx, es
  362. @@L3a:
  363.   mov [videoSegment], bx
  364.   mov [attribNl], ch
  365.   mov [attribInv], cl
  366.   mov [cursorShape], dx
  367.   mov es, [2Ch]                 ;Find COMSPEC
  368.   sub di, di
  369. @@L3:
  370.   mov si, OFFSET comspec$
  371.   mov cx, 8
  372.   repe cmpsb
  373.   jne @@L3
  374.   mov [comspecPtrOff], di
  375.   mov [comspecPtrSeg], es
  376.  
  377. InitFile:
  378.   mov dx, OFFSET fName          ;Open file and set up list of line pointers
  379.   cmp [fName?], 0               ;If no file name specified on command line,
  380.   jne @@L0
  381.   mov [noEscape?], -1           ;Prompt for it
  382.   call GetFileName
  383. @@L0:
  384.   call OpenFile
  385.   mov [lMargin], 0              ;Set initial margins
  386.   mov [rMargin], LINEWIDTH - 1
  387.   cmp [startInText?], 0
  388.   je NextKey
  389.   call ToggleWPMode
  390.  
  391. NextKey:
  392.   call Redraw                   ;Redraw screen, status line
  393. NextNoRedraw:
  394.   call DrawCursor               ;Place cursor
  395.   sub ah, ah                    ;Get keypress to AL
  396.   int 16h
  397.   or al, al                     ;Check for control codes
  398.   je IsAux
  399.   cmp al, ' '
  400.   jb IsCtrl
  401.   call Insert                   ;Insert or overwrite if none
  402.   jmp NextKey
  403.  
  404. IsAux:
  405.   xchg al, ah                   ;Get aux code
  406.   cmp al, 132
  407.   ja NextKey
  408.   mov si, OFFSET auxTable       ;Jump indirect to appropriate routine
  409. DoTableJump:
  410.   shl ax, 1
  411.   add si, ax
  412.   call [WORD si]
  413.   jmp NextKey
  414.  
  415. IsCtrl:
  416.   mov si, OFFSET ctrlTable      ;Jump to routine through table
  417.   sub ah, ah
  418.   jmp DoTableJump
  419.  
  420. InsertRaw:
  421.   call Shifted?                 ;Set flag if shifted
  422.   mov dl, al
  423.   sub ah, ah                    ;Get keypress to AL
  424.   int 16h
  425.   or al, al                     ;Check for aux code, ignore InsertRaw if found
  426.   je IsAux
  427.   cmp dl, 0                     ;If shift was down set high bit
  428.   jz @@L1
  429.   or al, 80h
  430. @@L1:
  431.   call Insert                   ;Insert
  432.   jmp NextKey
  433.  
  434. OtherFile:
  435. ;Open another file
  436.   call Save                     ;Save current file if altered
  437.   mov ax, [blockPtrsLast]       ;If block buffer is empty,
  438.   sub ax, OFFSET blockPtrs
  439.   jne @@L2
  440.   mov ax, [heapStart]           ; reset heap pointer to start
  441.   mov [heapPtr], ax
  442.   jmp GetOther                  ; prompt for new file name
  443. @@L2:
  444.   shr ax, 1                     ;Else move lines with pointers in block buffer
  445.   mov cx, ax                    ; to start of heap (load new file above them)
  446.   mov dl, 5
  447.   mul dl
  448.   add ax, [heapStart]           ;Calculate upper limit of target zone
  449.   mov [heapPtr], ax             ; which will also be new value of heap pointer
  450.   mov bx, OFFSET blockPtrs      ;For each pointer in block buffer,
  451. @@L3:
  452.   cmp [bx], ax                  ;If its line is already within target zone,
  453.   jae @@L4
  454.   mov es, [bx]                  ;Set high bit of first char in line to mark it
  455.   or [byte es:0], 80h           ; (we won't need to move these lines)
  456. @@L4:
  457.   inc bx                        ;Next pointer
  458.   inc bx
  459.   loop @@L3
  460.   push ds
  461.   mov bx, OFFSET blockPtrs      ;For each pointer in block buffer:
  462.   mov es, [heapStart]
  463. @@L4a:
  464.   test [byte es:0], 80h         ;If high bit set in target line,
  465.   jne @@L7                      ; line already in use, try next target line
  466.   mov ds, [cs:bx]               ;If high bit set in source line,
  467.   test [byte 0], 80h
  468.   je @@L5                       ; don't need to move it (already there)
  469.   inc bx                        ; Next source line, same target line
  470.   inc bx
  471.   jmp SHORT @@L8
  472. @@L5:
  473.   mov cx, 40                    ;Else move one line
  474.   sub si, si
  475.   sub di, di
  476.   rep movsw
  477.   mov [cs:bx], es               ;Update pointer
  478. @@L6:
  479.   inc bx                        ;Next block pointer
  480.   inc bx
  481. @@L7:
  482.   mov ax, es                    ;Next target line
  483.   add ax, 5
  484.   mov es, ax
  485. @@L8:
  486.   segcs                         ;Loop until all lines moved
  487.   cmp bx, [blockPtrsLast]
  488.   jb @@L4a
  489.   pop ds
  490.   mov bx, OFFSET blockPtrs      ;Reset high bits of all first chars set high
  491. @@L9:
  492.   mov es, [bx]
  493.   and [byte es:0], 7Fh
  494.   inc bx
  495.   inc bx
  496.   cmp bx, [blockPtrsLast]
  497.   jb @@L9
  498. GetOther:
  499.   mov [noEscape?], -1
  500.   mov dx, OFFSET fName          ;Prompt for new file name
  501.   call GetFileName
  502.   jmp SHORT OpenFile1           ;Read in new file above block buffer lines
  503.  
  504. OpenFile:
  505. ;Open file, load if found, then close.  Call with dx -> ASCIIZ file name.
  506.   mov ax, OFFSET blockPtrs      ;Reset block buffer pointer
  507.   mov [blockPtrsLast], ax
  508.   mov ax, [heapStart]           ;Begin loading at start of heap
  509.   mov [heapPtr], ax
  510. OpenFile1:
  511.   mov [newFile?], 0
  512.   mov [changed?], 0
  513.   mov ax, 3D80h                 ;Try to open file
  514.   int 21h
  515.   jnc OldFile
  516.   mov [newFile?], -1            ;If no such file, remind me to create a new one
  517. OpenNewFile:
  518.   call NewFile
  519.   jmp XOpenFile
  520. OldFile:
  521.   mov [fHandle], ax             ;Else save file handle
  522.   mov bx, OFFSET linePtrs       ;Read file in
  523.   mov dx, ax
  524.   call ReadFile
  525.   dec bx
  526.   dec bx
  527.   mov [lastLine], bx            ;Save index of last line
  528.   mov bx, [fHandle]             ;Close file
  529.   mov ah, 3Eh
  530.   int 21
  531. XOpenFile:
  532.   mov bx, OFFSET linePtrs       ;Reset row, screen pointers
  533.   mov [top], bx
  534.   mov es, [bx]
  535.   sub di, di
  536.   ret
  537.  
  538. GetFileName:
  539. ;Prompt for file name.  Abort if null name.  Call with buffer address in DX.
  540.   push si
  541.   push dx
  542.   mov si, OFFSET newFileMsg     ;Print prompt
  543.   call Prompt
  544.   pop dx
  545.   call GetString                ;Get file name
  546.   mov si, dx                    ;Convert to ASCIIZ
  547.   add si, ax
  548.   mov [BYTE si], 0
  549.   pop si
  550.   ret
  551.  
  552. GetString:
  553. ;Get string to [DX], return count (minus CR/LF) in AX.  Abort if null string.
  554.   push bx
  555.   push cx
  556.   push si
  557.   push di
  558.   push es
  559.   push dx
  560. @@L2:
  561.   mov dx, OFFSET pad            ;Get string
  562.   mov ah, 3Fh
  563.   sub bx, bx
  564.   mov cx, 20
  565.   int 21h
  566.   dec ax                        ;Strip CR/LF
  567.   dec ax
  568.   jnz @@L1                      ;Abort if null string
  569.   cmp [noEscape?], 0            ; unless escape precluded
  570.   je @@L0
  571.   call Beep
  572.   mov si, OFFSET newFileMsg
  573.   call Prompt
  574.   jmp @@L2
  575. @@L0:
  576.   mov si, OFFSET cancelledMsg
  577.   jmp Abort
  578. @@L1:
  579.   mov cx, ax                    ;Copy temporary copy of string to [DX]
  580.   pop dx
  581.   push ax
  582.   mov ax, ds
  583.   mov es, ax
  584.   mov si, OFFSET pad
  585.   mov di, dx
  586.   rep movsb
  587.   pop ax
  588.   pop es
  589.   pop di
  590.   pop si
  591.   pop cx
  592.   pop bx
  593.   mov [noEscape?], 0
  594.   ret
  595.  
  596. ReadFile:
  597. ;Load file with handle in DX, assigning segment pointers starting at BX
  598.   push es
  599.   mov ax, [heapPtr]
  600.   mov es, ax
  601.   sub cx, cx
  602.   sub di, di
  603. FillBuffer:
  604.   push bx                       ; Fill buffer
  605.   push cx
  606.   push dx
  607.   mov bx, dx
  608.   mov ah, 3Fh
  609.   mov cx, BUFFERLENGTH
  610.   mov dx, OFFSET buffer
  611.   int 21h
  612.   jnc @@L1                      ; Check for read error
  613.   jmp ReadError
  614. @@L1:
  615.   pop dx
  616.   pop cx
  617.   pop bx
  618.   mov si, OFFSET buffer         ; Set pointers
  619.   add ax, si
  620.   mov [bufferPtr], ax
  621.   cmp ax, OFFSET buffer         ;Exit if empty buffer
  622.   je EndOfFile
  623.   cmp [byte si], LF             ;Skip LF if first char in buffer
  624.   jne SHORT NextLine
  625.   inc si
  626. NextLine:
  627.   mov al, [si]                  ;Get next char
  628.   cmp al, CR                    ;If char is CR, end of line
  629.   jne @@L2
  630.   inc si                        ; move past CR
  631.   cmp [byte si], LF             ; and LF if present
  632.   jne @@L1
  633.   inc si
  634. @@L1:
  635.   call EndOfLine                ; pad out line with spaces and save it
  636.   jmp SHORT @@L3
  637. @@L2:
  638.   cmp al, HT                    ;Else if a tab, expand it
  639.   jne @@L2a
  640.   push cx
  641.   mov al, ' '
  642.   mov cl, [tabSize]
  643.   sub ch, ch
  644.   rep stosb
  645.   pop cx
  646.   sub cl, [tabSize]
  647.   sbb ch, 0
  648.   inc si
  649.   jmp SHORT @@L3
  650. @@L2a:
  651.   movsb                         ;Else add char to line
  652.   dec cx
  653. @@L3:
  654.   cmp si, [bufferPtr]           ;Loop until end of buffer
  655.   jb NextLine
  656.   cmp si, OFFSET ENDFBUFFER     ;If buffer less than full, indicates end of file
  657.   jae FillBuffer
  658. EndOfFile:
  659.   call EndOfLine                ;Finish up present line
  660.   mov [heapPtr], es             ;Update pointer to start of free heap space
  661.   pop es
  662.   ret
  663.  
  664. EndOfLine:
  665.   add cx, LINEWIDTH             ;Pad to end with spaces
  666.   jle @@L1                      ;Truncate lines longer than LINEWIDTH chars
  667.   mov al, ' '
  668.   rep stosb
  669. @@L1:
  670.   mov [bx], es                  ;Store segment of this line
  671.   mov ax, es                    ;Next line
  672.   add ax, 5
  673.   cmp ax, 0A000h                ;Out of room?
  674.   jb SHORT @@L2
  675.   jmp NoRoom
  676. @@L2:
  677.   mov es, ax
  678.   inc bx
  679.   inc bx
  680.   sub di, di
  681.   sub cx, cx
  682. Ret3:
  683.   ret
  684.  
  685. Redraw:
  686. ;Redraw screen and status line
  687.   mov [here], bx
  688.   mov [hereCol], di
  689.   push bx
  690.   push di
  691.   push ds
  692.   push es
  693.   push di
  694.   mov es, [videoSegment]        ;Get segment for display
  695.   mov si, OFFSET editingMsg     ;Refresh status line:  "Editing ..."
  696.   call Prompt
  697.   mov di, 34                    ;Tab to column 17
  698.   mov si, OFFSET fName          ; <file name>
  699.   mov ah, [attribInv]
  700. @@S1:
  701.   lodsb
  702.   or al, al
  703.   je @@S2
  704.   stosw
  705.   jmp @@S1
  706. @@S2:
  707.   add di, 6                     ;3 spaces
  708.   mov al, 'L'                   ;"L" <line #>
  709.   stosw
  710.   inc di
  711.   inc di
  712.   mov ax, bx
  713.   sub ax, OFFSET linePtrs
  714.   shr ax, 1
  715.   inc ax
  716.   call PrintInt
  717.   add di, 4                     ;2 spaces
  718.   mov al, 'C'                   ;"C" <column number>
  719.   mov ah, [attribInv]
  720.   stosw
  721.   inc di
  722.   inc di
  723.   pop ax                        ;Get copy of DI as cursor row
  724.   inc ax
  725.   call PrintInt
  726.   mov di, LINEWIDTH * 2 - 12    ;Tab to start of status chars display
  727.   mov al, 'I'                   ;Insert/Overwrite status
  728.   mov ah, [attribInv]
  729.   test [inserting?], -1
  730.   jne @@S3
  731.   mov al, 'O'
  732. @@S3:
  733.   stosw
  734.   mov al, 'C'                   ;Changed status
  735.   test [changed?], -1
  736.   jne @@S5
  737.   mov al, ' '
  738. @@S5:
  739.   stosw
  740.   mov al, 'A'                   ;Autoinsert status
  741.   test [autoIndent?], -1
  742.   jne @@S6
  743.   mov al, ' '
  744. @@S6:
  745.   stosw
  746.   mov al, ' '                   ;L margin set?
  747.   cmp [lMargin], 0
  748.   je @@S7
  749.   mov al, '['
  750. @@S7:
  751.   stosw
  752.   mov al, ' '                   ;R margin set?
  753.   cmp [rMargin], LINEWIDTH - 1
  754.   je @@S8
  755.   mov al, ']'
  756.   stosw
  757. @@S8:
  758.   segcs
  759.   mov al, [attribNl]            ;Mark margins as non-inv chars in status line
  760.   mov di, [lMargin]
  761.   add di, di
  762.   je @@S8a
  763.   inc di
  764.   stosb
  765. @@S8a:
  766.   mov di, [rMargin]
  767.   cmp di, LINEWIDTH - 1
  768.   je @@S8b
  769.   add di, di
  770.   inc di
  771.   stosb
  772. @@S8b:
  773.   mov di, LINEWIDTH * 2         ;Move to next display line
  774.   mov ax, [top]                 ;Compute bottom of screen
  775.   mov bx, ax
  776.   add ax, (SCREENLENGTH - 1) * 2
  777.   cmp ax, [lastLine]            ;If at end of file,
  778.   jle @@L0
  779.   mov ax, [lastLine]            ; stop at lastLine
  780. @@L0:
  781.   mov [bottom], ax
  782. @@L1:                           ;For each row
  783.   mov cx, LINEWIDTH             ;Count of chars per row
  784.   mov ds, [cs:bx]               ;Get pointer to screen line
  785.   sub si, si                    ;Initialize column counter
  786.   segcs
  787.   mov ah, [attribNl]            ;Attribute = inverse video if Marked
  788.   test [cs:marking?], -1
  789.   je @@L2
  790.   segcs
  791.   cmp bx, [mark]
  792.   je @@L1b
  793.   jb @@L1a
  794.   segcs
  795.   cmp bx, [here]
  796.   jbe @@L1b
  797.   jmp SHORT @@L2
  798. @@L1a:
  799.   segcs
  800.   cmp bx, [here]
  801.   jb @@L2
  802. @@L1b:
  803.   segcs
  804.   mov ah, [attribInv]
  805. @@L2:                           ;For each char, write char and attribute
  806.   lodsb
  807.   stosw
  808.   loop @@L2                     ;Next char
  809.   inc bx                        ;Next row
  810.   inc bx
  811.   segcs
  812.   cmp bx, [bottom]              ;Stop if screen full
  813.   jle @@L1
  814.   mov cx, LINEWIDTH * 2 * (SCREENLENGTH + 1)  ;Fill out screen with blanks
  815.   sub cx, di
  816.   shr cx, 1
  817.   segcs
  818.   mov ah, [attribNl]
  819.   mov al, ''
  820.   rep stosw
  821. @@L3:
  822.   pop es
  823.   pop ds
  824.   pop di
  825.   pop bx
  826.   ret
  827.  
  828. DrawCursor:
  829. ;Set cursor shape and place it on screen
  830.   push bx
  831.   mov cx, [cursorShape]         ;Set cursor shape: line for insert mode,
  832.   test [Inserting?], -1
  833.   jne @@L1
  834.   sub ch, ch                    ;Block for overwrite
  835. @@L1:
  836.   mov ah, 1
  837.   int 10h
  838.   sub bx, [top]                 ;Show cursor at current row, column
  839.   shr bx, 1
  840.   inc bx
  841.   mov dh, bl
  842.   mov ax, di
  843.   mov dl, al
  844.   mov ah, 2
  845.   mov bh, 0
  846.   int 10h
  847.   pop bx
  848.   ret
  849.  
  850. Print0:
  851.   call ClearStatus              ;Blank status line
  852.   sub di, di                    ;Starting at beginning of line ...
  853.  
  854. Print:
  855. ;Print string pointed to by SI on status line in inverse video, starting at DI
  856.   push es
  857.   mov es, [videoSegment]
  858.   lodsb                         ;Get count of string to be printed
  859.   mov cl, al
  860.   sub ch, ch
  861.   mov ah, [attribInv]            ;Attribute = inverse video
  862. @@L1:
  863.   lodsb
  864.   stosw
  865.   loop @@L1
  866.   pop es
  867.   ret
  868.  
  869. ClearStatus:
  870. ;Inverse-blank status line
  871.   push di
  872.   push es
  873.   mov es, [videoSegment]
  874.   mov ah, [attribInv]
  875.   mov al, ' '
  876.   mov cx, 80
  877.   sub di, di
  878.   rep stosw
  879.   pop es
  880.   pop di
  881.   ret
  882.  
  883. Cancel:
  884. ;Ctrl C routine
  885.   mov si, OFFSET ctrlCMsg       ;Abort with message ...
  886.  
  887. Abort:
  888. ;Print counted string pointed to by SI on status line and abort
  889.   call Print0                   ;Print error message ...
  890.  
  891. na:
  892. ;Unassigned key or other error.  Beep and abort.
  893.   call Beep                     ;Beep
  894.   mov sp, OFFSET STACKTOP       ;Reset stack pointer to top
  895.   mov bx, [here]                ;Retrieve cursor position in case it was trashed
  896.   mov di, [hereCol]
  897.   call DrawCursor
  898.   jmp NextNoRedraw              ;Restart main editing loop
  899.  
  900. Beep:
  901.   mov ah, 2                     ;Output a BELL
  902.   mov dl, BELL
  903.   int 21h
  904.   ret
  905.  
  906. Prompt:
  907.   push di
  908.   call Print0                   ;Print string at start of line
  909.   mov dx, di                    ;Set cursor to end of printed string ...
  910.   shr dl, 1
  911.   sub dh, dh
  912.   pop di
  913.  
  914. GotoXY:
  915. ;Position cursor at row, column given by DL, DH
  916.   push bx
  917.   mov ah, 2
  918.   sub bx, bx
  919.   int 10h
  920.   pop bx
  921.   ret
  922.  
  923. PrintInt:
  924. ;Print to ES:DI in inverse video the unsigned decimal integer in AX
  925.   sub dx, dx                    ;Start stack with a null
  926.   push dx
  927.   mov cx, 10                    ;Get remainders of successive divisions by 10
  928. @@L1:
  929.   div cx
  930.   add dl, '0'                   ;Convert to ASCII
  931.   mov dh, [attribInv]           ;Attribute is reverse video
  932.   push dx
  933.   sub dx, dx
  934.   or ax, ax
  935.   jne @@L1
  936.   pop ax                        ;Pop and print remainders in reverse order
  937. @@L2:
  938.   stosw
  939.   pop ax
  940.   or ax, ax
  941.   jne @@L2
  942.   ret
  943.  
  944. NewLineC:
  945. ;Jump here if file is changed by a command
  946.   mov [changed?], -1
  947. NewLine:
  948.   mov [justFound?], 0
  949. NewLine0:
  950.   cmp bx, OFFSET linePtrs       ;Check bounds, adjust if necessary
  951.   jge @@L1
  952.   mov bx, OFFSET linePtrs
  953. @@L1:
  954.   cmp bx, [lastLine]
  955.   jle @@L2
  956.   mov bx, [lastLine]
  957. @@L2:
  958.   mov ax, [top]
  959.   cmp bx, ax
  960.   jge @@L3
  961.   mov [top], bx
  962. @@L3:
  963.   add ax, (SCREENLENGTH-1)*2
  964.   cmp bx, ax
  965.   jle @@L4
  966.   mov ax, bx
  967.   sub ax, (SCREENLENGTH-1)*2
  968.   mov [top], ax
  969. @@L4:
  970.   mov es, [bx]                  ;Adjust ES to point to new line
  971.   ret
  972.  
  973. Left:
  974.   or di, di                     ;If at start of line,
  975.   jne @@L1
  976.   call Up                       ; move to end of line above
  977.   jmp EndLine
  978. @@L1:
  979.   dec di                        ; else just decrement cursor
  980. CursorMoved:
  981.   mov [justFound?], 0
  982.   ret
  983.  
  984. Right:
  985.   cmp di, LINEWIDTH - 1         ;If at end of line,
  986.   jne @@L1
  987.   sub di, di                    ; move to start of line below
  988.   jmp Down
  989. @@L1:
  990.   inc di                        ; else just increment cursor
  991.   jmp SHORT CursorMoved
  992.  
  993. LScanE:
  994. ;Scan left past first non-space or start of line
  995.   mov al, ' '
  996.   mov cx, di
  997.   inc cx
  998.   std
  999.   repe scasb
  1000.   cld
  1001.   ret
  1002.  
  1003. LScanNE:
  1004. ;Scan left past first space or start of line
  1005.   mov al, ' '
  1006.   mov cx, di
  1007.   inc cx
  1008.   std
  1009.   repne scasb
  1010.   cld
  1011.   ret
  1012.  
  1013. RScanE:
  1014. ;Scan right past first non-space or end of line
  1015.   mov al, ' '
  1016.   mov cx, LINEWIDTH
  1017.   sub cx, di
  1018.   repe scasb
  1019.   ret
  1020.  
  1021. RScanNE:
  1022. ;Scan right past first space or end of line
  1023.   mov al, ' '
  1024.   mov cx, LINEWIDTH
  1025.   sub cx, di
  1026.   repne scasb
  1027.   ret
  1028.  
  1029. WordLeft:
  1030. ;Move left one word
  1031.   or di, di                     ;Do nothing if at start of line
  1032.   je @@Lx
  1033.   mov [justFound?], 0
  1034.   dec di                        ;Else starting at char to left,
  1035.   call LScanE                   ; skip spaces until non-space
  1036.   inc di
  1037.   je @@Lx                       ; or start of line,
  1038.   call LScanNE                  ; then scan to next space or start of line
  1039.   jne @@L1
  1040.   inc di
  1041. @@L1:
  1042.   inc di
  1043. @@Lx:
  1044.   ret
  1045.  
  1046. WordRight:
  1047. ;Move right one word
  1048.   cmp di, LINEWIDTH - 1         ;Do nothing if at end of line
  1049.   je @@Lx
  1050.   mov [justFound?], 0
  1051.   call RScanNE                  ;Skip non-spaces until space
  1052.   jne @@L1                      ; or end of line,
  1053.   dec di
  1054.   call RScanE                   ; then scan to next non-space or end of line
  1055. @@L1:
  1056.   dec di
  1057. @@Lx:
  1058.   ret
  1059.  
  1060. HomeLine:
  1061. ;Move cursor to L margin
  1062.   mov di, [lMargin]
  1063.   mov [justFound?], 0
  1064.   ret
  1065.  
  1066. EndLine:
  1067. ;Move cursor to R margin or end of text on line (but not left of L margin)
  1068.   push cx
  1069.   mov [justFound?], 0
  1070.   mov di, [rMargin]             ;Start at R margin
  1071.   cmp [BYTE es:di], ' '         ;If non-blank, stop here
  1072.   jne @@L2
  1073.   call LScanE                   ;Skip all spaces until non-space
  1074.   je @@L1                       ; or beginning of line
  1075.   inc di
  1076. @@L1:
  1077.   inc di
  1078. @@L2:
  1079.   cmp di, [lMargin]             ;If left of L margin, set to L margin
  1080.   jae @@L3
  1081.   mov di, [lMargin]
  1082. @@L3:
  1083.   pop cx
  1084. Ret2:
  1085.   ret
  1086.  
  1087. Up:
  1088. ;Move cursor up one line
  1089.   cmp bx, OFFSET linePtrs       ;If at top of file already, do nothing
  1090.   je Ret2
  1091.   dec bx
  1092.   dec bx
  1093.   jmp NewLine
  1094.  
  1095. Down:
  1096. ;Move cursor down one line
  1097.   cmp bx, [lastLine]            ;If at last line already, do nothing
  1098.   je Ret2
  1099.   inc bx
  1100.   inc bx
  1101.   jmp NewLine
  1102.  
  1103. PageUp:
  1104. ;Move cursor up one page
  1105.   sub bx, (SCREENLENGTH-1)*2
  1106.   jmp NewLine
  1107.  
  1108. PageDown:
  1109. ;Move cursor down one page
  1110.   add bx, (SCREENLENGTH-1)*2
  1111.   jmp NewLine
  1112.  
  1113. TopFile:
  1114. ;Move cursor to top of file
  1115.   mov bx, OFFSET linePtrs
  1116.   mov [top], bx
  1117.   call HomeLine
  1118.   jmp NewLine
  1119.  
  1120. BottomFile:
  1121. ;Move cursor to bottom of file
  1122.   mov bx, [lastLine]
  1123.   mov es, [bx]
  1124.   mov ax, bx
  1125.   sub ax, (SCREENLENGTH-1)*2
  1126.   cmp ax, OFFSET linePtrs
  1127.   ja @@L1
  1128.   mov ax, OFFSET linePtrs
  1129. @@L1:
  1130.   mov [top], ax
  1131.   call EndLine
  1132.   jmp NewLine
  1133.  
  1134. Tab:
  1135. ;Tab right
  1136.   mov [justFound?], 0
  1137.   mov ax, di                    ;Advance di to next tab stop
  1138.   mov cl, [tabSize]
  1139.   div cl
  1140.   sub cl, ah
  1141.   sub ch, ch
  1142.   add di, cx
  1143.   cmp di, LINEWIDTH             ;If past end of line,
  1144.   jl @@L1
  1145.   mov di, LINEWIDTH - 1         ;Set cursor at end of line
  1146. @@L1:
  1147.   ret
  1148.  
  1149. ReverseTab:
  1150. ;Tab left
  1151.   mov [justFound?], 0
  1152.   mov ax, di                    ;Decrement di to nearest tab stop
  1153.   dec al
  1154.   div [tabSize]
  1155.   mov al, ah
  1156.   sub ah, ah
  1157.   inc al
  1158.   sub di, ax
  1159.   jnc @@L1                      ;Set to start of line if past start
  1160.   sub di, di
  1161. @@L1:
  1162.   ret
  1163.  
  1164. SetLMargin:
  1165. ;Toggle left margin between 0 and present cursor setting
  1166.   cmp [lMargin], 0
  1167.   je @@L1
  1168.   mov [lMargin], 0
  1169.   ret
  1170. @@L1:
  1171.   mov [lMargin], di
  1172.   ret
  1173.  
  1174. SetRMargin:
  1175. ;Toggle right margin between LINEWIDTH-1 and present cursor setting
  1176.   cmp [rMargin], LINEWIDTH-1
  1177.   je @@L1
  1178.   mov [rMargin], LINEWIDTH-1
  1179.   ret
  1180. @@L1:
  1181.   mov [rMargin], di
  1182.   ret
  1183.  
  1184. ToggleWPMode:
  1185. ;Toggle word processing and programming defaults
  1186.   cmp [lMargin], 0
  1187.   jne @@L1
  1188.   cmp [rMargin], LINEWIDTH-1
  1189.   jne @@L1
  1190.   sub ah, ah
  1191.   mov al, [zLMargin]
  1192.   mov [lMargin], ax
  1193.   mov al, [zRMargin]
  1194.   mov [rMargin], ax
  1195.   mov [autoIndent?], 0
  1196.   jmp HomeLine
  1197. @@L1:
  1198.   mov [lMargin], 0
  1199.   mov [rMargin], LINEWIDTH-1
  1200.   mov [autoIndent?], -1
  1201.   jmp HomeLine
  1202.  
  1203. CRet:
  1204. ;Split line at cursor
  1205.   push ds
  1206.   push es
  1207.   push di
  1208.   push es
  1209.   call AddBlankLine             ;Start a new line below current one, ->ES:DI
  1210.   pop ds                        ;DS:SI := current cursor position
  1211.   pop si
  1212.   push di
  1213.   mov cx, LINEWIDTH             ;CX := # chars left on line
  1214.   sub cx, si
  1215.   je @@L2
  1216. @@L1:
  1217.   movsb                         ;Split line,
  1218.   mov [byte si - 1], ' '        ; blank original to end from cursor
  1219.   loop @@L1
  1220. @@L2:
  1221.   pop di
  1222.   pop es
  1223.   pop ds
  1224.   jmp NewLineC
  1225.  
  1226. AddBlankLine:
  1227. ;Insert a new blank line below current one
  1228.   mov cx, 1                     ;Make room for new entry in linePtr
  1229.   call OpenRow
  1230.   inc bx
  1231.   inc bx
  1232.   mov ax, [heapPtr]
  1233.   jmp SHORT BlankLine
  1234.  
  1235. NewFile:
  1236. ;Set up initial blank line of a new file
  1237.   mov ax, [heapStart]           ;Set ES and [bx] to available heap
  1238.   mov bx, OFFSET linePtrs
  1239.   mov [lastLine], bx
  1240. BlankLine:
  1241.   mov [bx], ax
  1242.   mov es, ax
  1243.   add ax, 5
  1244.   mov [heapPtr], ax             ;Update heap pointer (segment value only)
  1245. BlankThisLine:
  1246.   sub di, di                    ;Blank new line
  1247.   mov cx, LINEWIDTH
  1248.   mov al, ' '
  1249.   rep stosb
  1250.   mov di, [lMargin]             ;Home cursor on new line
  1251.   test [autoIndent?], -1        ; or if in autoindent mode,
  1252.   je @@Lx
  1253.   cmp bx, OFFSET linePtrs       ; and this is not first line in file,
  1254.   je @@Lx
  1255.   mov es, [bx - 2]              ; line up with first char of line above
  1256.   call RScanE
  1257.   mov es, [bx]
  1258.   je @@L1                       ; unless above line is blank
  1259.   dec di
  1260.   cmp di, [lMargin]             ; or first char is left of L margin
  1261.   jae @@Lx
  1262. @@L1:
  1263.   mov di, [lMargin]             ; in which case use L margin
  1264. @@Lx:
  1265.   ret
  1266.  
  1267. OpenRow:
  1268. ;Open CX lines at BX in linePtrs
  1269.   push cx
  1270.   push di
  1271.   push es
  1272.   mov ax, ds                    ;DS, ES -> data segment (for linePtr)
  1273.   mov es, ax
  1274.   mov si, [lastLine]            ;SI points to last line's segment pointer
  1275.   mov di, si                    ;DI points CX lines beyond that
  1276.   add di, cx
  1277.   add di, cx
  1278.   mov [lastLine], di            ;Point lastLine to new last line
  1279.   mov cx, si                    ;Count = # lines from here to end
  1280.   sub cx, bx
  1281.   shr cx, 1
  1282.   inc cx
  1283.   std
  1284.   rep movsw                     ;Move array elements up
  1285.   cld
  1286.   pop es
  1287.   pop di
  1288.   pop cx
  1289.   ret
  1290.  
  1291. Backspace:
  1292. ;Delete char to left of cursor
  1293.   mov ax, di                    ;Unless at first character of file,
  1294.   add ax, bx
  1295.   sub ax, OFFSET linePtrs
  1296.   jz Ret1                       ; do Left then Delete
  1297.   mov [justFound?], 0
  1298.   push di
  1299.   call Left
  1300.   pop ax                        ;Don't do Join if already at end of line ...
  1301.   or ax, ax
  1302.   jne Delete0
  1303.  
  1304. Delete:
  1305. ;Delete char at cursor
  1306.   mov dx, di                    ;Save cursor column
  1307.   cmp [BYTE es:di], ' '         ;If deleting a space at end of line,
  1308.   jne Delete0
  1309.   call RScanE
  1310.   mov di, dx                    ; join line below
  1311.   je Join
  1312. Delete0:
  1313.   push di                       ; else slide text left
  1314.   push cx
  1315.   push ds
  1316.   mov cx, LINEWIDTH - 1
  1317.   sub cx, di
  1318.   mov si, di
  1319.   inc si
  1320.   mov ax, es
  1321.   mov ds, ax
  1322.   rep movsb
  1323.   mov [BYTE di], ' '            ;Blank last character on line
  1324.   pop ds
  1325.   pop cx
  1326.   pop di
  1327.   mov [changed?], -1
  1328. Ret1:
  1329.   ret
  1330.  
  1331. UndeleteLine:
  1332.   mov bp, [blockPtrsLast]       ;Abort if no lines are in buffer
  1333.   cmp bp, OFFSET blockPtrs
  1334.   ja @@L0
  1335.   jmp Beep
  1336. @@L0:
  1337.   dec bp                        ;Else move pointer to top line of delete buffer
  1338.   dec bp
  1339.   mov [blockPtrsLast], bp
  1340.   cmp di, [lMargin]             ;If cursor is at or before L margin,
  1341.   ja @@L1
  1342.   mov cx, 1
  1343.   call OpenRow                  ;Start new row below current one
  1344.   mov [bx+2], es                ;Swap rows to insert undeleted above current
  1345.   mov ax, [bp]                  ;Retrieve and store pointer to undeleted line
  1346.   mov [bx], ax
  1347.   jmp NewLine
  1348. @@L1:
  1349.   mov cx, LINEWIDTH             ;Cursor past start of line
  1350.   sub cx, di                    ;Copy popped line over current one
  1351.   push di
  1352.   push ds
  1353.   mov ds, [bp]
  1354.   sub si, si
  1355.   rep movsb
  1356.   pop ds
  1357.   pop di
  1358.   ret
  1359.  
  1360. Join:
  1361. ;Join lower line to current line at cursor
  1362.   cmp bx, [lastLine]            ;Abort if this is the last line of the file
  1363.   je @@Lx
  1364.   push di                       ;Save registers
  1365.   push ds
  1366.   push di
  1367.   push es
  1368.   mov es, [bx + 2]              ;Get next line's segment
  1369.   push es                       ;Save a copy
  1370.   mov dx, di                    ;Get length of lower line:
  1371.   call EndLine                  ;Find first non-space char from end
  1372.   add dx, di                    ;If concatenated line is too long, abort.
  1373.   cmp dx, LINEWIDTH
  1374.   jbe @@L0
  1375.   call Beep
  1376.   pop ax
  1377.   pop es
  1378.   pop di
  1379.   pop ds
  1380.   pop ax
  1381.   jmp Ret1
  1382. @@L0:
  1383.   mov cx, di                    ;Count = lower line length
  1384.   sub si, si                    ;Source = start of lower line
  1385.   pop ds
  1386.   pop es                        ;Destination = present cursor location
  1387.   pop di
  1388.   rep movsb                     ;Concatenate lines
  1389.   pop ds
  1390.   inc bx                        ;Delete lower line
  1391.   inc bx
  1392.   call DeleteLineNS
  1393.   cmp bx, [lastLine]
  1394.   je @@L1
  1395.   dec bx
  1396.   dec bx
  1397. @@L1:
  1398.   pop di                        ;Restore pointers and return
  1399. @@Lx:
  1400.   jmp NewLine
  1401.  
  1402. Insert:
  1403. ;Insert or overwrite at cursor
  1404.   mov [justFound?], 0
  1405.   test [inserting?], -1         ;If inserting, open up space for new character
  1406.   jz Insert1
  1407.   mov si, [RMargin]             ;If line is full, split it
  1408.   cmp [BYTE es:si], ' '
  1409.   je Insert0
  1410.   push ax
  1411.   push bx
  1412.   push di
  1413.   call CRet
  1414.   pop di
  1415.   pop bx
  1416.   call NewLine
  1417.   pop ax
  1418.   jmp SHORT Insert1
  1419. Insert0:
  1420.   push ax
  1421.   push cx
  1422.   push ds
  1423.   mov ax, es
  1424.   mov ds, ax
  1425.   mov si, LINEWIDTH - 1
  1426.   mov cx, si
  1427.   sub cx, di
  1428.   mov di, si
  1429.   dec si
  1430.   std
  1431.   rep movsb
  1432.   cld
  1433.   pop ds
  1434.   pop cx
  1435.   pop ax
  1436. Insert1:
  1437.   stosb                         ;Add character
  1438.   mov [changed?], -1
  1439.   cmp di, [rMargin]             ;Wrap if at R margin
  1440.   ja WrapLine
  1441.   ret
  1442.  
  1443. WrapLine:
  1444. ;Wrap last word on current line
  1445.   cmp [BYTE es:di-1], ' '
  1446.   je @@L1
  1447.   call WordLeft
  1448. @@L1:
  1449.   call CRet
  1450.   jmp EndLine
  1451.  
  1452. Wrap:
  1453. ;Wrap paragraph starting at present line
  1454.   mov di, [rMargin]             ;Start at R margin of present line
  1455.   cmp bx, [lastLine]            ;Quit if we're at end of file
  1456.   je @@Lx
  1457. @@L1:
  1458.   mov dx, di
  1459.   call RScanE                   ;Is there text between here and end of line?
  1460.   cmp di, LINEWIDTH
  1461.   mov di, dx
  1462.   je @@L2
  1463.   call LScanNE                  ;Yes.  Is there a space at which to split line?
  1464.   or di, di
  1465.   mov di, dx
  1466.   jle @@Lx                      ;No, stop wrapping
  1467.   call FindBreak                ;Yes, split this line, drop to lower line
  1468.   call CRet
  1469.   jmp Wrap
  1470. @@L2:
  1471.   call EndLine                  ;Put cursor after end of text on line.
  1472.   mov al, [es:di-1]             ;If last char is in {.;:!?}, add two spaces
  1473.   cmp al, 40h
  1474.   jae @@L2b
  1475.   cmp al, '.'
  1476.   je @@L2a
  1477.   cmp al, ';'
  1478.   je @@L2a
  1479.   cmp al, ':'
  1480.   je @@L2a
  1481.   cmp al, '!'
  1482.   je @@L2a
  1483.   cmp al, '?'
  1484.   jne @@L2b
  1485. @@L2a:
  1486.   inc di
  1487. @@L2b:
  1488.   inc di                        ;After other chars, just add one space
  1489.   mov dx, [rMargin]             ;Calculate spaces remaining on upper line ->DX
  1490.   sub dx, di
  1491.   ja @@L3                       ;If no room for more text, next line
  1492.   call Down
  1493.   call KeepWrapping?
  1494.   jnc @@Lx
  1495.   jmp Wrap
  1496. @@L3:
  1497.   mov [topSegPtr], bx           ;Save pointers for this line
  1498.   mov [topSeg], es
  1499.   mov [topIndex], di
  1500.   call Down                     ;Drop down to next line
  1501.   call KeepWrapping?            ;Does text start at L margin?
  1502.   jc @@L4
  1503. @@Lx:
  1504.   jmp NewLine                   ;No, we're done
  1505. @@L4:
  1506.   add di, dx                    ;Yes, move words up from lower line
  1507.   call FindBreak                ;Find right place to break line
  1508.   mov dx, di                    ;Set up pointers and count for move
  1509.   mov si, [lMargin]
  1510.   sub bp, si
  1511.   jnz @@L4a                     ;If nothing will fit, next line
  1512.   jmp Wrap
  1513. @@L4a:
  1514.   mov ax, es
  1515.   mov di, [topIndex]
  1516.   mov es, [topSeg]
  1517.   mov bx, [topSegPtr]
  1518.   mov ds, ax
  1519.   mov cx, bp
  1520.   rep movsb                     ;Move part of lower line up
  1521.   mov cx, cs
  1522.   mov ds, cx
  1523.   cmp dx, LINEWIDTH - 1         ;If nothing left on lower line,
  1524.   jne @@L5
  1525.   call Down
  1526.   call DeleteLine               ;Delete it
  1527.   cmp bx, [lastLine]            ;Done if that was last line
  1528.   je @@Lx
  1529.   mov es, [topSeg]              ;Get top line back and keep wrapping
  1530.   mov bx, [topSegPtr]
  1531.   jmp Wrap
  1532. @@L5:
  1533.   call Down                     ;Else slide lower line left
  1534.   mov si, dx
  1535.   mov di, [lMargin]
  1536.   call CloseGap
  1537.   jmp Wrap                      ;Continue wrapping with lower line
  1538.  
  1539. KeepWrapping?:
  1540. ;Set DI to L margin.  Return C = 1 if line <- BX has text starting at L margin.
  1541.   mov di, [lMargin]
  1542.   cmp [BYTE es:di], ' '         ;Fail if space at margin
  1543.   je @@Lx
  1544.   or di, di
  1545.   je @@L1
  1546.   push di
  1547.   dec di                        ; or chars before margin
  1548.   call LScanE
  1549.   pop di
  1550.   jne @@Lx
  1551. @@L1:
  1552.   stc                           ; else return C = 1
  1553.   db 3Ch                        ;'cmp al, ?' trick to skip one byte
  1554. @@Lx:
  1555.   clc
  1556.   ret
  1557.  
  1558. FindBreak:
  1559. ;Find place to break line while wrapping.  Return BP = last char to move.
  1560.   cmp [BYTE es:di], ' '
  1561.   je @@L1
  1562.   inc di
  1563.   call WordLeft
  1564.   mov bp, di
  1565.   ret
  1566. @@L1:
  1567.   mov bp, di
  1568.   jmp WordRight
  1569.  
  1570. DeleteToEOL:
  1571. ;Delete from cursor to end of line
  1572.   mov [justFound?], 0
  1573.   push bx                       ;Save regs to return to current cursor position
  1574.   push di
  1575.   push es
  1576.   push [word autoIndent?]       ;Turn autoIndent off
  1577.   mov [autoIndent?], 0
  1578.   call Cret                     ;Do Enter then delete lower line
  1579.   call DeleteWordL
  1580.   call DeleteLine
  1581.   pop [word autoIndent?]
  1582.   pop es
  1583.   pop di
  1584.   pop bx
  1585.   jmp NewLine
  1586.  
  1587. DeleteLine:
  1588. ;Delete cursor line and append to buffer
  1589.   mov [changed?], -1
  1590.   cmp bx, [lastLine]            ;If last line of file, just blank it
  1591.   jne @@L1
  1592.   jmp BlankThisLine
  1593. @@L1:
  1594.   mov bp, [blockPtrsLast]       ;Save segment of current line in delete buffer
  1595.   mov [bp], es
  1596.   inc bp
  1597.   inc bp
  1598.   mov [blockPtrsLast], bp
  1599. DeleteLineNS:                   ;Enter here if we don't want to save line
  1600.   mov di, bx                    ;Delete line:  destination = this line
  1601.   mov si, di                    ;Source = next line
  1602.   inc si
  1603.   inc si
  1604.   mov cx, [lastLine]            ;Count = number of lines from here to end
  1605.   mov ax, cx
  1606.   dec ax
  1607.   dec ax
  1608.   mov [lastLine], ax
  1609.   sub cx, bx
  1610.   shr cx, 1
  1611.   mov ax, ds                    ;Move line segment values above cursor down
  1612.   mov es, ax
  1613.   rep movsw
  1614.   mov di, [lMargin]             ;Home cursor on new line
  1615.   jmp NewLine
  1616.  
  1617. DeleteWordL:
  1618. ;Delete left to space or column zero
  1619.   mov ah, 2                     ;Check for Ctrl key down.  ^[ or ESC?
  1620.   int 16h                       ;If ^[, delete word left (ignore ESC)
  1621.   and al, 4
  1622.   je DWLx
  1623.   mov si, di                    ;Save cursor column
  1624.   call WordLeft                 ;Tab left one word
  1625. CloseGap:
  1626.   push di                       ;Close gap between di and si cursor positions
  1627.   mov cx, LINEWIDTH
  1628.   sub cx, si
  1629.   push ds
  1630.   mov ax, es
  1631.   mov ds, ax
  1632.   rep movsb
  1633.   mov cx, LINEWIDTH             ;Pad end of line with spaces
  1634.   sub cx, di
  1635.   mov al, ' '
  1636.   rep stosb
  1637.   pop ds
  1638.   pop di
  1639.   mov [changed?], -1
  1640. DWLx:
  1641.   ret
  1642.  
  1643. DeleteWordR:
  1644. ;Delete right to space or end of line
  1645.   mov si, di                    ;Save cursor
  1646.   push di
  1647.   call WordRight                ;Tab right one word
  1648.   xchg si, di                   ;Close up space between si and di
  1649.   pop di
  1650.   jmp CloseGap
  1651.  
  1652. ToggleIns:
  1653.   not [inserting?]
  1654.   ret
  1655.  
  1656. Jump:
  1657. ;Jump to line number n
  1658.   mov si, OFFSET gotoMsg
  1659.   call Prompt
  1660.   call GetInt
  1661.   dec ax
  1662.   shl ax, 1
  1663.   mov bx, ax
  1664.   add bx, OFFSET linePtrs
  1665.   mov [justFound?], 0
  1666.   jmp JL1                       ;Jump to address
  1667.  
  1668. GetInt:
  1669. ;Get a decimal integer from keyboard to AX.  Carry set on improper input.
  1670. ;Abort if null input.
  1671.   push bx
  1672.   push cx
  1673.   push dx
  1674.   push si
  1675.   mov dx, OFFSET buffer
  1676.   call GetString                ;Input a string
  1677.   mov cx, ax                    ;Construct integer a digit at a time
  1678.   mov si, OFFSET buffer
  1679.   sub ax, ax
  1680.   mov bh, 10
  1681. @@L1:
  1682.   mov bl, [si]                  ;Get next char
  1683.   inc si
  1684.   sub bl, '0'
  1685.   jc @@Lx                       ;Exit with carry set if not a digit
  1686.   cmp bl, '9'
  1687.   cmc
  1688.   jc @@Lx
  1689.   mul bh                        ;AX := AX + (new digit - '0')
  1690.   add al, bl
  1691.   adc ah, 0
  1692.   jc @@Lx                       ;Check for overflow
  1693.   loop @@L1                     ;Next char
  1694. @@Lx:
  1695.   pop si                        ;Return with int in AX, carry set if error
  1696.   pop dx
  1697.   pop cx
  1698.   pop bx
  1699.   ret
  1700. @@La:
  1701.   mov si, OFFSET cancelledMsg
  1702.   jmp Abort
  1703.  
  1704. SetLabel:
  1705. ;Set label 0-9 at current line
  1706.   call GetLabel
  1707.   mov [si], bx
  1708.   ret
  1709.  
  1710. GotoLabel:
  1711. ;Goto label 0-9 previously set by SetLabel
  1712.   call GetLabel
  1713.   cmp [WORD si], 0              ;Cancel if label not assigned
  1714.   je JLx
  1715.   mov bx, [si]                  ;Retrieve address
  1716.   mov [justFound?], 0
  1717. JL1:
  1718.   mov ax, bx
  1719.   sub ax, 8                     ;Make cursor line fifth from top
  1720.   cmp ax, OFFSET linePtrs
  1721.   jge @@L1
  1722.   mov ax, OFFSET linePtrs
  1723. @@L1:
  1724.   mov [top], ax
  1725. JLx:
  1726.   jmp NewLine0
  1727.  
  1728. GetLabel:
  1729.   mov si, OFFSET setLabelMsg
  1730.   call Prompt
  1731.   mov ah, 8                     ;Get char from keyboard
  1732.   int 21h
  1733.   mov dl, al                    ;Save copy to echo
  1734.   sub al, '0'                   ;Don't accept input if not a digit
  1735.   jl GetLabel
  1736.   cmp al, 9
  1737.   jg GetLabel
  1738.   mov ah, 2
  1739.   mov cl, al
  1740.   int 21h
  1741.   mov si, OFFSET LabelTable     ;Form index into LabelTable
  1742.   shl cl, 1
  1743.   sub ch, ch
  1744.   add si, cx                    ;Return address of label storage in SI
  1745.   ret
  1746.  
  1747. SetTabs:
  1748. ;Set tab width
  1749.   mov si, OFFSET setTabsMsg
  1750.   call Prompt
  1751.   call GetInt
  1752.   mov [tabSize], al
  1753.   ret
  1754.  
  1755. AutoIndent:
  1756. ;Toggle autoindent mode
  1757.   not [autoIndent?]
  1758.   ret
  1759.  
  1760. Kill:
  1761. ;Clear changed? flag so file changes will be discarded on exit
  1762.   mov [changed?], 0
  1763.   ret
  1764.  
  1765. Save:
  1766. ;Write lines to file, renaming old version with .BAK extension
  1767.   cmp [changed?], 0             ;If no changes, done.
  1768.   je XSave
  1769.   push dx
  1770.   push di
  1771.   push es
  1772.   push bx
  1773.   mov al, [newFile?]            ;If a new file, create it first
  1774.   or al, [isBAKed?]             ;If already BAKed up, no .BAK needed
  1775.   jnz DoSave
  1776.   mov ax, ds                    ;Else make new ASCIIZ str with .BAK extension
  1777.   mov es, ax
  1778.   mov si, OFFSET fName
  1779.   mov di, OFFSET fNameBAK
  1780. @@L1:
  1781.   lodsb
  1782.   cmp al, '.'
  1783.   je @@L2
  1784.   or al, al
  1785.   je @@L2
  1786.   stosb
  1787.   jmp SHORT @@L1
  1788. @@L2:
  1789.   mov cx, 5
  1790.   mov si, OFFSET BAK
  1791.   rep movsb
  1792.   mov ah, 41h                   ;Delete old back-up copy if present
  1793.   mov dx, OFFSET fNameBAK
  1794.   int 21h
  1795.   mov dx, OFFSET fName          ;Rename current file to file.BAK
  1796.   mov di, OFFSET fNameBAK
  1797.   mov ah, 56h
  1798.   int 21h
  1799. DoSave:
  1800.   mov ah, 3Ch                   ;CREATe new file with old name
  1801.   sub cx, cx
  1802.   mov dx, OFFSET fName
  1803.   int 21h
  1804.   jc CantOpen
  1805.   mov [fHandle], ax
  1806.   mov [isBAKed?], -1            ;Set flag so we only make .BAK file once
  1807.   mov bx, OFFSET linePtrs       ;Write file
  1808.   call WriteFile
  1809.   mov ah, 3Eh                   ;Close file
  1810.   mov bx, [fHandle]
  1811.   int 21h
  1812.   pop bx
  1813.   pop es
  1814.   pop di
  1815.   pop dx
  1816.   mov [changed?], 0
  1817. XSave:
  1818.   ret
  1819.  
  1820. WriteFile:
  1821. ;Write lines out to file [fHandle] starting at BX and ending at [lastLine]
  1822.   push es
  1823.   push di
  1824.   mov di, OFFSET buffer
  1825. @@L1:
  1826.   mov si, di                    ;Preserve file buffer pointer
  1827.   mov es, [bx]                  ;Strip trailing blanks
  1828.   mov cx, LINEWIDTH
  1829.   mov di, LINEWIDTH - 1
  1830.   mov al, ' '
  1831.   std
  1832.   repe scasb
  1833.   cld
  1834.   je @@L1a
  1835.   inc cx
  1836. @@L1a:
  1837.   mov ax, ds                    ;Copy line to file buffer
  1838.   mov dx, es
  1839.   mov es, ax
  1840.   mov ds, dx
  1841.   mov di, si
  1842.   sub si, si
  1843.   rep movsb
  1844.   mov ax, CRLF                  ;Stick a CRLF on the end
  1845.   stosw
  1846.   mov ax, ds
  1847.   mov dx, es
  1848.   mov es, ax
  1849.   mov ds, dx
  1850.   cmp di, OFFSET Buffer + BUFFERLENGTH - 80  ;If buffer is almost full,
  1851.   jl @@L2
  1852.   call WriteBuffer              ; write it
  1853. @@L2:
  1854.   inc bx                        ;Next line, loop until all lines are written
  1855.   inc bx
  1856.   cmp bx, [lastLine]
  1857.   jle @@L1
  1858.   dec di                        ;Delete last CR, LF
  1859.   dec di
  1860.   call WriteBuffer              ;Write final partial buffer to file and exit
  1861.   pop di
  1862.   pop es
  1863.   ret
  1864.  
  1865. FileError:
  1866.   mov si, OFFSET fileErrorMsg
  1867.   jmp Abort
  1868. CantOpen:
  1869.   mov si, OFFSET cantOpenMsg
  1870.   jmp Abort
  1871. NoRoom:
  1872.   mov si, OFFSET noRoomMsg
  1873.   jmp Abort
  1874. ReadError:
  1875.   mov si, OFFSET rdErrorMsg
  1876.   jmp Abort
  1877.  
  1878. WriteBuffer:
  1879. ;Write text in buffer to disk
  1880.   push bx
  1881.   mov ah, 40h
  1882.   mov bx, [fHandle]
  1883.   mov cx, di
  1884.   mov dx, OFFSET Buffer
  1885.   sub cx, dx
  1886.   jz @@L1
  1887.   int 21h
  1888.   jc FileError
  1889.   mov di, OFFSET Buffer
  1890. @@L1:
  1891.   pop bx
  1892.   ret
  1893.  
  1894. Exit:
  1895.   call Save                     ;Save file if changed
  1896.   call RestoreCursor
  1897.   mov ax, 4C00h                 ;Bye!
  1898.   int 21h
  1899.  
  1900. RestoreCursor:
  1901.   mov cx, [cursorShape]         ;Restore standard cursor size
  1902.   mov ah, 1
  1903.   int 10h
  1904.   mov dx, 1800h                 ;Put cursor at bottom of screen
  1905.   sub bh, bh
  1906.   mov ah, 2
  1907.   int 10h
  1908.   ret
  1909.  
  1910. BeginBlock:
  1911. ;Start marking block for block operation
  1912.   mov [marking?], -1
  1913.   mov [mark], bx
  1914.   ret
  1915.  
  1916. Unmark:
  1917. ;Clear marking
  1918.   mov [marking?], 0
  1919.   ret
  1920.  
  1921. InsertBlock:
  1922. ;Insert from buffer or named file
  1923.   push bx
  1924.   call FileOrBuffer?            ;From file or buffer?
  1925.   je InsertBuffer
  1926.   mov dx, OFFSET fNameTemp      ;If file, open it
  1927.   mov ax, 3D00h
  1928.   int 21h
  1929.   jnc @@L1
  1930.   jmp CantOpen
  1931. @@L1:
  1932.   mov dx, ax                    ;Load file
  1933.   mov bx, OFFSET blockPtrs
  1934.   mov di, bx
  1935.   call ReadFile
  1936.   mov cx, bx
  1937.   mov bx, dx                    ;Close file
  1938.   mov ah, 3Eh
  1939.   int 21h
  1940.   jmp SHORT DoInsert
  1941. InsertBuffer:                   ;Insert from buffer
  1942.   mov bp, [blockPtrsLast]       ;Abort if empty
  1943.   cmp bp, OFFSET blockPtrs
  1944.   jne @@L0
  1945.   pop bx
  1946.   jmp na
  1947. @@L0:
  1948.   test [needCopies?], -1        ;If not just moving lines, need to duplicate
  1949.   jz @@L2
  1950.   push bx
  1951.   push es
  1952.   push ds
  1953.   mov bx, bp
  1954.   mov dx, [heapPtr]
  1955. @@L1:
  1956.   dec bx                        ;Copy contents of buffered lines to new ones
  1957.   dec bx
  1958.   mov ds, [cs:bx]
  1959.   sub si, si
  1960.   mov es, dx
  1961.   sub di, di
  1962.   mov [cs:bx], es
  1963.   mov cx, LINEWIDTH
  1964.   rep movsb
  1965.   add dx, 5
  1966.   cmp dx, 0A000h
  1967.   jb @@L1a
  1968.   jmp NoRoom
  1969. @@L1a:
  1970.   cmp bx, OFFSET blockPtrs
  1971.   ja @@L1
  1972.   pop ds
  1973.   pop es
  1974.   pop bx
  1975.   mov [heapPtr], dx
  1976. @@L2:
  1977.   mov [needCopies?], -1
  1978.   mov cx, bp
  1979. DoInsert:
  1980.   pop bx
  1981.   sub cx, OFFSET blockPtrs      ;Get count of lines to move
  1982.   shr cx, 1
  1983.   call OpenRow                  ;Open that much room in array of seg pointers
  1984.   mov si, OFFSET blockPtrs      ;Copy new lines into opening
  1985.   mov di, bx
  1986.   mov ax, ds
  1987.   mov es, ax
  1988.   rep movsw
  1989.   sub di, di
  1990.   jmp NewLineC
  1991.  
  1992. FileOrBuffer?:
  1993. ;Prompt for file name if Shift is down, put it in fNameTemp.
  1994. ;If return with Z set, Shift was up, indicating buffer is to be used.
  1995.   call Shifted?                 ;If shift is down, prompt for file name
  1996.   jz Ret4
  1997.   mov dx, OFFSET fNameTemp
  1998.   call GetFileName
  1999.   jnz Ret4                      ;If null string returned, abort
  2000.   mov si, OFFSET cancelledMsg
  2001.   jmp Abort
  2002.  
  2003. Shifted?:
  2004. ;Get shift key status, returned in AL.  Z set if no shift.
  2005.   mov ah, 2
  2006.   int 16h
  2007.   and al, 3
  2008. Ret4:
  2009.   ret
  2010.  
  2011. EmptyBuffer:
  2012. ;If Shifted, write block buffer to file, else discard
  2013.   mov bp, [blockPtrsLast]       ;Abort if buffer is empty
  2014.   cmp bp, OFFSET blockPtrs
  2015.   jne @@L0
  2016.   jmp Beep
  2017. @@L0:
  2018.   call Shifted?                 ;If shifted, write to file
  2019.   je @@L1
  2020.   push bx
  2021.   mov dx, OFFSET fNameTemp
  2022.   call GetFileName
  2023.   mov si, OFFSET blockPtrs
  2024.   mov bx, bp
  2025.   dec bx
  2026.   dec bx
  2027.   call WriteBlock
  2028.   pop bx
  2029. @@L1:
  2030.   mov ax, OFFSET blockPtrs      ;Else just reset buffer pointer
  2031.   mov [blockPtrsLast], ax
  2032. @@Lx:
  2033.   ret
  2034.  
  2035. WriteBlock:
  2036. ;Write block to file.  SI -> starting seg pointer, BX -> ending seg pointer.
  2037.   push [lastLine]               ;Copy block buffered lines to file:
  2038.   push [fHandle]
  2039.   mov ah, 3Ch                   ;CREATe file
  2040.   sub cx, cx
  2041.   mov dx, OFFSET fNameTemp
  2042.   int 21h
  2043.   jnc @@L1
  2044.   jmp CantOpen
  2045. @@L1:
  2046.   mov [fHandle], ax             ;Write it
  2047.   mov [lastLine], bx
  2048.   mov bx, si
  2049.   call WriteFile
  2050.   mov bx, [fHandle]             ;Close it
  2051.   mov ah, 3Eh
  2052.   int 21h
  2053.   pop [fHandle]
  2054.   pop [lastLine]
  2055.   ret
  2056.  
  2057. Copy:
  2058. ;Copy marked lines, to file if shift is down, otherwise to buffer.
  2059.   test [marking?], -1          ;Abort with a beep if not already marking,
  2060.   jnz @@L1
  2061.   mov si, OFFSET notMarkingMsg
  2062.   jmp Abort
  2063. @@L1:
  2064.   mov si, [mark]
  2065.   cmp bx, si                    ;If mark comes after here, exchange
  2066.   jae @@L2
  2067.   xchg bx, si
  2068.   mov [mark], si                ; save in this order for possible delete
  2069. @@L2:
  2070.   push bx
  2071.   push di
  2072.   push es
  2073.   call FileOrBuffer?            ;If Shift key was down when command entered,
  2074.   je @@L4
  2075.   call WriteBlock
  2076.   mov di, OFFSET blockPtrs
  2077.   jmp @@Lx
  2078. @@L4:
  2079.   mov cx, bx                    ;If no Shift, move marked lines to buffer
  2080.   sub cx, si
  2081.   shr cx, 1
  2082.   inc cx
  2083.   mov di, OFFSET blockPtrs
  2084.   mov ax, ds
  2085.   mov es, ax
  2086.   rep movsw
  2087. @@Lx:
  2088.   mov [blockPtrsLast], di       ;Save pointer to last line
  2089.   pop es
  2090.   pop di
  2091.   pop bx
  2092.   mov [marking?], 0
  2093.   ret
  2094.  
  2095. DeleteBlock:
  2096. ;Do a Copy, then delete copied lines
  2097.   call Copy                     ;Copy block to file or buffer
  2098.   mov si, bx                    ;Close up copied lines:
  2099.   inc si                        ;SI = cursor line + 2
  2100.   inc si
  2101.   mov di, [mark]                ;DI = start of marking
  2102.   mov cx, [lastLine]            ;CX = number of lines from here to end
  2103.   sub cx, bx
  2104.   push es
  2105.   mov ax, ds
  2106.   mov es, ax
  2107.   rep movsb
  2108.   pop es
  2109.   dec di
  2110.   dec di
  2111.   cmp di, OFFSET linePtrs       ;If whole file deleted, start new file
  2112.   jae @@L1
  2113.   call NewFile
  2114.   jmp NewLineC
  2115. @@L1:
  2116.   mov [lastLine], di            ;Else store index of new last line
  2117.   mov di, [lMargin]             ;Point cursor to start of old marked line
  2118.   mov bx, [mark]
  2119.   mov [needCopies?], 0
  2120.   jmp NewLineC
  2121.  
  2122. Find:
  2123. ;Prompt for and find next <string>.  If Shifted, reuse last <string>.
  2124.   push bx
  2125.   push es
  2126.   push di
  2127.   call Right
  2128.   test [autoReplace?], -1       ;If doing replace all, bypass shift check
  2129.   js @@L0
  2130.   jnz @@L1
  2131.   call Shifted?                 ;If Shifted,
  2132.   jnz @@L1
  2133. @@L0:
  2134.   mov si, OFFSET findMsg        ;Get search string
  2135.   mov dx, OFFSET findString
  2136.   call GetCountedString
  2137. @@L1:
  2138.   mov si, OFFSET findString
  2139.   lodsw
  2140.   dec al
  2141.   mov dl, al
  2142.   mov al, ah
  2143.   mov cx, LINEWIDTH
  2144.   sub cx, di
  2145. FindLoop:
  2146.   repne scasb                   ;Scan for first char of Find string
  2147.   jne FindNextLine
  2148.   push di                       ;Once found, compare rest of string
  2149.   mov dh, cl
  2150.   mov cl, dl
  2151.   mov si, OFFSET findString + 2
  2152.   repe cmpsb
  2153.   je Found
  2154.   pop di                        ;Match failed.  Scan again for 1st char.
  2155.   mov cl, dh
  2156.   jmp FindLoop
  2157. FindNextLine:
  2158.   inc bx                        ;Search next line (until EOF)
  2159.   inc bx
  2160.   mov es, [bx]
  2161.   sub di, di
  2162.   mov cl, LINEWIDTH
  2163.   cmp bx, [lastLine]
  2164.   jbe FindLoop
  2165.   mov si, OFFSET notFoundMsg    ;Not found
  2166.   test [autoReplace?], -1       ;If doing auto-replace, return
  2167.   jz @@L1
  2168.   mov [autoReplace?], 0
  2169.   pop di
  2170.   pop es
  2171.   pop bx
  2172.   ret
  2173. @@L1:
  2174.   call Print0                   ;Else restore cursor, abort with error message
  2175.   pop di
  2176.   pop es
  2177.   pop bx
  2178.   jmp na
  2179. Found:
  2180.   pop di
  2181.   dec di
  2182.   add sp, 6
  2183.   mov [justFound?], -1
  2184.   mov ax, bx                    ;Show found line 5 below top of screen
  2185.   jmp JL1
  2186.  
  2187. GetCountedString:
  2188. ;Print prompt string at [SI], read counted string into [DX].
  2189. ;Returns count (minus CR/LF) in AL.  DX is advanced one to start of string.
  2190.   push di
  2191.   push dx
  2192.   call Prompt                   ;Display prompt
  2193.   pop dx
  2194.   mov di, dx
  2195.   inc dx
  2196.   call GetString                ;Get input string
  2197.   mov [di], al                  ;Store count in front of string
  2198.   pop di
  2199.   ret
  2200.  
  2201. Replace:
  2202.   push di
  2203.   test [autoReplace?], -1       ;If using auto-replace command,
  2204.   jz @@L0
  2205.   jns @@L2                      ;Skip shift check
  2206.   mov [autoReplace?], 1
  2207.   jmp SHORT @@L1a               ;Get replace string if shifted and first pass
  2208. @@L0:
  2209.   test [justFound?], -1         ;Beep if not immediately preceded by a Find
  2210.   jnz @@L1
  2211. @@LE:
  2212.   pop di
  2213.   jmp na
  2214. @@L1:
  2215.   call Shifted?                 ;If not Shifted, prompt for replace string
  2216.   jnz @@L2
  2217. @@L1a:
  2218.   mov si, OFFSET replaceMsg
  2219.   mov dx, OFFSET replaceString
  2220.   call GetCountedString
  2221. @@L2:
  2222.   mov si, OFFSET replaceString
  2223.   lodsb
  2224.   sub ah, ah
  2225.   mov dx, si
  2226.   push ax
  2227.   push dx
  2228.   sub ch, ch                    ;Compare lengths of find and replace strings
  2229.   mov cl, al
  2230.   sub cl, [byte findString]     ;If replace string is longer,
  2231.   je @@L6
  2232.   jb @@L4
  2233.   xchg dx, di
  2234.   call EndLine                  ; make sure there will be enough room on line
  2235.   xchg dx, di
  2236.   add dl, cl
  2237.   cmp dl, LINEWIDTH
  2238.   ja @@LE
  2239. @@L3:
  2240.   call Insert0                  ; then insert extra characters
  2241.   loop @@L3
  2242.   jmp SHORT @@L6
  2243. @@L4:
  2244.   neg cl                        ;If shorter, delete difference
  2245. @@L5:
  2246.   call Delete0
  2247.   loop @@L5
  2248. @@L6:
  2249.   pop si                        ;Now copy new string over old
  2250.   pop cx
  2251.   sub ch, ch
  2252.   pop di
  2253.   rep movsb
  2254.   jmp NewLineC
  2255.  
  2256. ReplaceAll:
  2257. ;Find and replace all.  If shift not down, prompt for strings.
  2258.   push [top]
  2259.   push es
  2260.   push di
  2261.   push bx
  2262.   mov [autoReplace?], 1         ;Set flag: 1 = no shift, -1 = shift
  2263.   call Shifted?
  2264.   jne @@L1
  2265.   mov [autoReplace?], -1
  2266. @@L1:
  2267.   call Find                     ;Find/replace until flag reset by not found
  2268.   test [autoReplace?], -1
  2269.   jz @@Lx
  2270.   call Replace
  2271.   jmp @@L1
  2272. @@Lx:
  2273.   pop bx                        ;Restore original position
  2274.   pop di
  2275.   pop es
  2276.   pop [top]
  2277.   push si
  2278.   call ReDraw                   ;Refresh screen with any changes
  2279.   pop si
  2280.   push di
  2281.   call Print0                   ;Show notFoundMsg and exit
  2282.   pop di
  2283.   jmp NextNoRedraw
  2284.  
  2285. Help:
  2286.   push es
  2287.   push di
  2288.   mov es, [videoSegment]
  2289.   mov di, 160
  2290.   mov si, OFFSET helpMsg
  2291.   mov cx, 80 * 24
  2292.   mov ah, [attribNl]
  2293. @@L1:
  2294.   lodsb
  2295.   stosw
  2296.   loop @@L1
  2297.   mov si, OFFSET anyKeyMsg
  2298.   call Print0
  2299.   sub ah, ah
  2300.   int 16h
  2301.   pop di
  2302.   pop es
  2303.   ret
  2304.  
  2305. F3BAT:
  2306.   mov dl, '3'
  2307.   jmp SHORT FnBAT
  2308.  
  2309. F4BAT:
  2310.   mov dl, '4'
  2311.   jmp SHORT FnBAT
  2312.  
  2313. F5BAT:
  2314.   mov dl, '5'
  2315.   jmp SHORT FnBAT
  2316.  
  2317. F6BAT:
  2318.   mov dl, '6'
  2319.  
  2320. FnBAT:
  2321. ;Execute 'EFn.BAT f'  where n = DL and f = current file name minus extension
  2322.   push es
  2323.   push di
  2324.   call Save                     ;Save work
  2325.   mov [EXECFNumber], dl         ;Which .BAT file?
  2326.   mov ax, cs                    ;Copy file name to command line string
  2327.   mov es, ax
  2328.   mov di, OFFSET EXECFileName
  2329.   mov si, OFFSET fName
  2330.   sub cl, cl
  2331. @@L1:
  2332.   lodsb
  2333.   or al, al                     ; up to '.' or null (ie, omit extension)
  2334.   je @@L2
  2335.   cmp al, '.'
  2336.   je @@L2
  2337.   stosb
  2338.   inc cl
  2339.   jmp @@L1
  2340. @@L2:
  2341.   mov al, CR
  2342.   stosb
  2343.   add cl, 11
  2344.   mov [EXECBAT], cl             ;Store count to include file name
  2345.   pop di
  2346.   pop es
  2347.   mov ax, OFFSET EXECBAT
  2348.   jmp SHORT Shell1
  2349.  
  2350. Shell:
  2351. ;Shell to DOS
  2352.   mov ax, OFFSET EXECParams     ;Point to null command line tail
  2353. Shell1:
  2354.   mov [EXECCmdLineOff], ax
  2355.   push bx                       ;Save regs
  2356.   push es
  2357.   push di
  2358.   call Shifted?                 ;If shift is down,
  2359.   jz @@L1
  2360.   call Save                     ; save file being edited and release its RAM
  2361.   mov bx, ((PROGLENGTH + ESSENTIALS) SHR 4) + 1
  2362.   mov [swapped?], -1
  2363.   jmp SHORT @@L2
  2364. @@L1:
  2365.   mov bx, [heapPtr]             ; else keep file and buffers in memory
  2366.   mov ax, cs
  2367.   sub bx, ax
  2368.   mov [swapped?], 0
  2369. @@L2:
  2370.   mov ax, cs                    ;Free all unneeded memory
  2371.   mov es, ax
  2372.   mov ah, 4Ah
  2373.   int 21h
  2374.   call RestoreCursor            ;Restore cursor
  2375.   mov [SPTemp], sp              ;Do EXEC fn
  2376.   mov dx, [comspecPtrOff]
  2377.   mov ds, [comspecPtrSeg]
  2378.   mov bx, OFFSET EXECParams
  2379.   mov ax, 4B00h
  2380.   int 21h
  2381.   mov ax, cs                    ;Reclaim memory
  2382.   mov ds, ax
  2383.   mov ss, ax
  2384.   mov sp, [spTemp]
  2385.   mov ah, 4Ah
  2386.   mov bx, -1
  2387.   int 21h
  2388.   mov ah, 4Ah
  2389.   int 21h
  2390.   cmp [swapped?], 0             ;If edited file was swapped out,
  2391.   je XEXEC
  2392.   mov dx, OFFSET fName          ;Read it back in
  2393.   call OpenFile
  2394. XEXEC:
  2395.   pop di                        ;Restore regs and return
  2396.   pop es
  2397.   pop bx
  2398.   ret
  2399.  
  2400. EndOfProgram:
  2401. END Orig